{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.可视化校对，查看编号是否正确（可以执行完第2步后，再执行）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "处理 6/10: 2010072795_FG_004_7_1_7\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeQAAAHqCAYAAADVpD2JAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8ekN5oAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA7TElEQVR4nO3deXhU1eH/8c+9d/ZsEFYRQRAUBCtq1WqRRQH3HdS6otVqpXUpKm6/KoILde23tlqtS0WsFVoUlaqouNa6tFi1aBUtiAiKCYGss93z+yPJkCETkkBiDvH9ep55YO6cOffMkvu599xz7jjGGCMAANCh3I5uAAAAIJABALACgQwAgAUIZAAALEAgAwBgAQIZAAALEMgAAFiAQAYAwAIEMgAAFiCQge+4HXfcUddee21HN6PVXnrpJTmOo3nz5jVbdvLkydpxxx3brS077rijjjjiiHarP5cxY8Zo+PDhzZZbvny5HMfRgw8+2Op11D/3lltuabbstddeK8dxspbtuOOOmjx5cqvXW//c9nhPx4wZI8dx5DjOFtd/0UUXZerIz89vs7a1WSC//fbb+tnPfqZhw4YpLy9P/fr10wknnKCPP/44Z/kPP/xQhxxyiPLz81VcXKzTTjtNa9eubVTu+uuv11FHHaVevXrJcZzNbjhWrVqlE044QV26dFFhYaGOPvpoffbZZznL3nfffRo6dKgikYgGDx6s3/zmN43K7Ljjjpk3fdPb4MGDM+VWrlyp6dOna5999lHXrl3VvXt3jRkzRs8//3yjOht+GTa9BYPBrLIVFRW66KKL1LdvX4XDYQ0dOlR33XVXozoffPDBJutcs2ZNk+9XLpMnT26yrmeeeSar7IYNG3T99dfr+9//voqKihQOh9W/f3+deOKJevrpp1u13np///vfNXLkSMViMfXu3VsXXHCBKioqGpWLx+OaNm2a+vTpo2g0qn333VeLFi3abN1lZWXq2bNnizfiDdVv/Ju6XX/99a2q76677tKkSZPUr18/OY6zxRutzX32juNozpw5W1RvLi+88ILOOuss7bzzzorFYho4cKDOPvtsrV69eovrvPjii7XnnnuquLhYsVhMQ4cO1bXXXpvzMwdyWbp0qa699lotX768xc8ZMmSIZs+erUsuuSRreVPb/PPOOy+r3GmnnabZs2frgAMOaIuXkBFoq4pmzZql119/XZMmTdL3vvc9rVmzRnfeeaf23HNP/eMf/8jak/viiy80atQoFRUV6YYbblBFRYVuueUWvf/++3rrrbcUCoUyZa+++mr17t1be+yxh5599tkm119RUaGxY8dq/fr1uvLKKxUMBnX77bdr9OjRevfdd9WtW7dM2d///vc677zzdPzxx+sXv/iFXn31VV1wwQWqqqrStGnTMuXuuOOORhuGFStW6Oqrr9aECRMyy5544gnNmjVLxxxzjM444wylUik99NBDGj9+vO6//36deeaZmbJXXXWVzj777Kw6Kysrdd5552XVmU6ndfDBB+udd97RlClTNHjwYD377LM6//zztW7dOl155ZWN3oPrrrtOAwYMyFrWpUuXJt+zpoTDYf3hD39otHz33XfP/H/ZsmU6+OCDtWLFCh177LE6/fTTlZ+fr5UrV2rhwoU64ogj9NBDD+m0005r8XrfffddHXTQQRo6dKhuu+02ffHFF7rlllv0ySef6G9/+1tW2cmTJ2vevHm66KKLNHjwYD344IM67LDDtHjxYo0cOTJn/b/85S9VVVXV4vY0NHToUM2ePbvR8tmzZ+u5557L+uxaYtasWSovL9c+++yzVYE2atSonO26/fbb9e9//1sHHXTQFte9qWnTpqm0tFSTJk3S4MGD9dlnn+nOO+/UU089pXfffVe9e/dudZ1vv/22DjjgAJ155pmKRCJasmSJbrrpJj3//PN65ZVX5Lp04m2t/v37q7q6utEO/7fhv//9b7t/hkuXLtX06dM1ZsyYFveC9OrVS6eeemrOx0aMGKGpU6dmLdt5552z7u+1117aa6+99Pzzz+tf//rXFrU7J9NGXn/9dROPx7OWffzxxyYcDptTTjkla/lPf/pTE41GzYoVKzLLFi1aZCSZ3//+91ll//e//xljjFm7dq2RZK655pqc6581a5aRZN56663Msg8//NB4nmeuuOKKzLKqqirTrVs3c/jhh2c9/5RTTjF5eXmmtLR0s69zxowZRpJ5/fXXM8s++OADs3bt2qxyNTU1ZsiQIaZv376brc8YY2bPnm0kmTlz5mSWPfbYY0aSue+++7LKHn/88SYSiZivvvoqs+yBBx4wkszbb7/d7Lqac8YZZ5i8vLzNlkkmk2b48OEmLy/PvPbaaznLPPvss2bhwoWtWvehhx5qtttuO7N+/frMsnvvvddIMs8++2xm2ZtvvmkkmZtvvjmzrLq62uy0005mv/32y1n3+++/bwKBgLnuuuuMJDN37txWta0pgwYNMoMHD27185YvX2583zfGGJOXl2fOOOOMNmmPMbXf8YKCAjN+/PgWle/fv3+Tf1cNvfzyyyadTjdaJslcddVVW9LUnG655RYjybzxxhubLbd48eIWf5ZnnHGG6d+/fxu1sLH+/fs32qa0t9GjR5thw4a16zr+97//Nfpba8o111xj2jBSWvyezp0710gyixcvblG9o0ePNqNHj96qddZryfayNdps12X//ffPOrKVpMGDB2vYsGH68MMPs5b/5S9/0RFHHKF+/fpllo0bN04777yzHnvssayyLd3jmTdvnvbee2/tvffemWVDhgzRQQcdlFXn4sWLVVJSovPPPz/r+VOmTFFlZWWzXa2PPPKIBgwYoP333z+zbNiwYerevXtWuXA4rMMOO0xffPGFysvLm60zLy9PRx99dGbZq6++Kkk66aSTssqedNJJqqmp0RNPPJGzrvLycqXT6c2ub2vNnTtXH3zwgf7f//t/+uEPf5izzIQJE3TooYe2uM4NGzZo0aJFOvXUU1VYWJhZXn/k3fAznDdvnjzP009+8pPMskgkoh//+Md64403tHLlykb1X3jhhTr22GPbtIvprbfe0rJly3TKKae0+rn9+/dvdL6trTz55JMqLy/fonZtzqhRoxod7YwaNUrFxcVZf+MPPPCAHMfR/fffn1X2hhtukOM4Wrhw4WbXU/83X1ZW1qJ2pdNpXXnllerdu7fy8vJ01FFH5fwObKqyslJTp07VDjvsoHA4rF122UW33HKLTI4fwHv44Ye1zz77KBaLqWvXrho1apSee+65zdb/xz/+UYFAQJdeemlm2aOPPqq99tpLBQUFKiws1G677aZf//rXLXqdTVm6dKnGjh2rWCym7bffXr/61a+yHm/qHPLcuXO16667KhKJaPjw4Zo/f/5mz7Xfc8892mmnnRQOh7X33nvr7bffbrZtuc4hv/feexo9erSi0aj69u2rmTNnZr4zubqdX3vtNe2zzz6KRCIaOHCgHnroocxjDz74oCZNmiRJGjt2bKaL+aWXXmq2bZuTSCRUWVm5VXVsiXbtSzDG6KuvvsoKq1WrVunrr7/W97///Ubl99lnHy1ZsqTV6/F9X++9916TdX766aeZUKyvf9Oye+21l1zX3ez6lyxZog8//FAnn3xyi9q1Zs0axWIxxWKxJsusXbtWixYt0jHHHKO8vLzM8ng8Ls/zGu3k1Nf1z3/+s1FdY8eOVWFhoWKxmI466ih98sknLWpnLt98803Wbf369ZnHnnzySUlqsstnS7z//vtKpVKNPpdQKKQRI0ZkfS5LlizRzjvvnBXcUu1nLdV2fTc0d+5c/f3vf2+0odpa9edn2zr4ttacOXMUjUZ13HHHtfu6KioqVFFRkfU3fuaZZ+qII47QL37xi0wwvv/++5o+fbp+/OMf67DDDsuqI5VK6ZtvvtGXX36p5557TldffbUKCgoyn2dzrr/+ej399NOaNm2aLrjgAi1atEjjxo1TdXV1k88xxuioo47S7bffrkMOOUS33XabdtllF1166aX6xS9+kVV2+vTpOu200xQMBnXddddp+vTp2mGHHfTiiy82Wf8999yjM888U5dffrluvvlmSdKiRYv0ox/9SF27dtWsWbN00003acyYMXr99ddb9DpzWbdunQ455BDtvvvuuvXWWzVkyBBNmzat0SmeTT399NM68cQTFQwGdeONN+q4447Tj3/845zbFan2oOHmm2/Wueeeq5kzZ2r58uU67rjjlEwmW9XeVatWaezYsfrPf/6jK664QhdffLHmzJnT5E7JsmXLNHHiRI0fP1633nqrunbtqsmTJ+s///mPpNodwgsuuECSdOWVV2r27NmaPXu2hg4d2qp2NfTiiy8qFospPz9fO+6441bvMLVKmx1r51DfFduw2/Xtt982ksxDDz3UqPyll15qJJmamppGj22uy7r+seuuu67RY7/97W+NJPPRRx8ZY4yZMmWK8TwvZ3t79OhhTjrppCZfz9SpU40ks3Tp0ibL1Pvkk09MJBIxp5122mbL/eY3vzGSGnXv3nrrrUaSefXVV7OWX3755UaSOeKIIzLL/vznP5vJkyebP/7xj2b+/Pnm6quvNrFYzHTv3t18/vnnzba1oTPOOMNIanRr2MWzxx57mC5dujR6bkVFhVm7dm3m1rDruTn13U6vvPJKo8cmTZpkevfunbk/bNgwc+CBBzYq95///MdIMnfffXdmWVVVlenXr1/mtEVrujk3J5VKmV69epl99tlnq+oxpm27rEtKSkwoFDInnHBCi5/T0i7rXOpP4bzwwgtZy1evXm2Ki4vN+PHjTTweN3vssYfp169fzu/EG2+8kfVd22WXXVrU/Vj/WW6//fZmw4YNmeX1p3t+/etfZ5Zt2mX9+OOPG0lm5syZWXVOnDjROI5jli1bZoyp/Tt2Xdcce+yxjbrr6085GJPd1fnrX//aOI5jZsyYkVX+wgsvNIWFhSaVSjX72lpi9OjRjbal8Xjc9O7d2xx//PGZZfXdzg888EBm2W677Wb69u1rysvLM8teeuklIynrfap/brdu3bJO5z3xxBNGknnyySczy3J1Wffv3z/ru/3zn//cOI5jlixZkllWUlJiiouLjaTMKcr65266Tfj6669NOBw2U6dOzSxryy7rI4880syaNcs8/vjj5r777jMHHHCAkWQuu+yynOWt7bLe1EcffaQpU6Zov/320xlnnJFZXr/XGg6HGz0nEolklWmp1tRZXV3d6KizYdmm1u37vh599FHtscceze59VVVVadKkSYpGo7rppps2W/aRRx5Rjx49NH78+KzlJ598soqKinTWWWdp0aJFWr58ue655x797ne/y3o9knTCCSfogQce0Omnn65jjjlGM2bM0LPPPquSkpJWj/6Vat+HRYsWZd1uvfXWzOMbNmzIOdT/qquuUo8ePTK3lvYkNHw9TX2GDV9vdXV1i78/N910k5LJZM5BcFvjhRde0FdffWXd0fG8efOUSCS+lXa98sormj59uk444QQdeOCBWY/17t1bv/3tb7Vo0SIdcMABevfdd3X//fc36tWQpF133VWLFi3S448/rssuu0x5eXmtGmV9+umnq6CgIHN/4sSJ2m677TbbNb5w4UJ5npc5uqo3depUGWMyR5iPP/64fN/XL3/5y0bd9blOOfzqV7/ShRdeqFmzZunqq6/OeqxLly6qrKxsdjZAa+Tn52f1VIVCIe2zzz5Nzi6RpC+//FLvv/9+5nRQvdGjR2u33XbL+ZwTTzxRXbt2zdyvP/WzufXk8swzz2i//fbTiBEjMsuKi4ub/L7uuuuuWaeZevTooV122aXV622pBQsW6LLLLtPRRx+ts846Sy+//LIOPvjgzCDT9tYugbxmzRodfvjhKioqypzvqxeNRiXVdsluqqamJqtMS7Wmzmg0qkQikbOempqaJtf98ssva9WqVc1u6NLptE466SQtXbpU8+bNU58+fZos+9lnn+mNN97QiSeeqEAge8B77969tWDBAsXjcU2YMEEDBgzQpZdempme1dzct5EjR2rffffNOfWqOZ7nady4cVm3vfbaK/N4QUFBzg3m+eefnwnwXr16tWqdzX2GDT+XaDTaos96+fLluvnmm3X99de36VxBqbZb2PM8nXjiiW1a79aaM2eOiouLW3X+fkt89NFHOvbYYzV8+PCcI/Kl2vEOhx9+uN566y2dc845TY74Liws1Lhx43T00Udr1qxZmjp1qo4++mj9+9//blFbGk5BlGqDctCgQZudBrNixQr16dMnK8glZXa2V6xYIUn69NNP5bqudt1112bb8fLLL2vatGmaNm1a1nnjeueff7523nlnHXrooerbt6/OOuusRlMJW6tv376Ndgy6du2qdevWNfmc+tc2aNCgRo/lWiYpa7xP/TokbXY9Ta17a9Zbv+7WrndLOY6jiy++WKlUaqvPS7dEmwfy+vXrdeihh6qsrEzPPPNMo0DabrvtJCnnVI/Vq1eruLg459HP5tQ/p6k6JWXasd122ymdTuvrr7/OKpdIJFRSUtJkgM6ZM0eu6+pHP/rRZttyzjnn6KmnntKDDz7Y6KhhU4888oikps9Bjho1Sp999pmWLFmi1157TatWrdIPfvADSY2H4eeyww47qLS0tNlyrTVkyBCVlZVp1apVWct33nnnTIDXH622VHPfi4afy3bbbdeiz/qXv/yltt9+e40ZM0bLly/X8uXLM/Oy165dq+XLl8v3/Va1U6o9Ap8/f77GjRvX6h2P9vT555/r1Vdf1aRJk9p1isvKlSs1YcIEFRUVaeHChY1CrV5JSYneeecdSbUDj1r6Xtef+3700UfbpsHfkmHDhmmXXXbR7Nmz9b///a/R4z179tS7776rBQsW6KijjtLixYt16KGHZvUgtlbDg52GTI6BaVvj21qPLettaIcddpCkdtmWbqpNA7mmpkZHHnmkPv74Yz311FM59yq333579ejRI/OH2tBbb72V1ZXRUq7rarfddstZ55tvvqmBAwdmNhr19W9a9p133pHv+znXH4/H9Ze//EVjxozZ7BHvpZdeqgceeEC33357s8Et1QbyTjvtlAnZXDzP04gRI/TDH/5Q+fn5mSPecePGNVv/Z599ph49ejRbrrXqr27TlhedGD58uAKBQKPPJZFI6N133836XEaMGKGPP/5YGzZsyCr75ptvZh6XagNq2bJlGjhwoAYMGKABAwZkPpfzzz9fAwYMaFRHSyxYsKBdRjFvrT/96U8yxrRru0pKSjRhwgTF43E9++yzmR2pXKZMmaLy8nLdeOONeu2113THHXe0aB3xeFy+72cNJNycTQcvGmO0bNmyzc7Q6N+/v7788stGMyA++uijzOOStNNOO8n3fS1durTZdnTv3l3PP/+8gsGgDjroIH355ZeNyoRCIR155JH63e9+p08//VTnnnuuHnroIS1btqzZ+ttK/WvLtc72bkf//v3bfL3tNVuhXn33eHtsSzfVZoGcTqd14okn6o033tDcuXO13377NVn2+OOP11NPPZU1NeGFF17Qxx9/nBnC3loTJ07U22+/nbVB/+9//6sXX3wxq84DDzxQxcXFja54dddddykWi+nwww9vVPfChQtVVla22Q3dzTffrFtuuUVXXnmlLrzwwmbb29oR21LtUd2sWbP0ve99LyuQc13hbOHChfrnP/+pQw45pMX1t9QJJ5ygXXfdVTNmzNA//vGPnGVauwdbVFSkcePG6eGHH87aSM6ePVsVFRVZn+HEiROVTqd1zz33ZJbF43E98MAD2nfffTN7tDNnztT8+fOzbjNmzJAkXXbZZZo/f37WyPaWeuSRRxSLxXTssce2+rnt6ZFHHlG/fv2avDDK1qqsrNRhhx2mVatWaeHChY26ihuaN2+e/vznP+umm27S5ZdfrpNOOklXX3111pX7ysrKco7Sre8CzzVrIpeHHnoo6zszb948rV69erPd9ocddpjS6bTuvPPOrOW33367HMfJPPeYY46R67q67rrrGh3h5/qO9+3bV88//7yqq6s1fvx4lZSUZB5r+H+p9kDie9/7nqTcp2raS58+fTR8+HA99NBDWaeeXn75Zb3//vvtuu6DDz5Yb7zxRtZMiNLS0q3aua//G27pNLmmlJaWNpoymkwmddNNNykUCmns2LFbVX9LtNmVuqZOnaoFCxboyCOPVGlpqR5++OGsxxsOPLjyyis1d+5cjR07VhdeeKEqKip08803a7fddsu6qpVUu0FesWJF5gpLr7zyimbOnCmp9vJl9Xt7559/vu69914dfvjhuuSSSxQMBnXbbbepV69eWVddiUajmjFjhqZMmaJJkybp4IMP1quvvqqHH35Y119/vYqLixu9tjlz5igcDuv444/P+drnz5+vyy67TIMHD9bQoUMbvfbx48c36tpsyZSZ0aNHa7/99tOgQYO0Zs0a3XPPPaqoqNBTTz2VNcBk//331x577JG5hOW//vUv3X///dphhx3afDCTJAWDQc2fP18HH3ywRo4cqeOOO04HHHCA8vLytGrVKi1YsECff/55zp2bzbn++uu1//77a/To0frJT36iL774QrfeeqsmTJiQtWOx7777atKkSbriiiv09ddfa9CgQfrjH/+o5cuX67777suUyxVM9Vcu23vvvXXMMce0+rWXlpbqb3/7m44//vitOi/95JNPZs6RJpNJvffee5nv9VFHHZXZULfUBx98oPfee0+XX355ux0xnHLKKXrrrbd01lln6cMPP8yae5yfn595P7/++mv99Kc/1dixY/Wzn/1MknTnnXdq8eLFmjx5sl577TW5rquXXnpJF1xwgSZOnKjBgwcrkUjo1Vdf1V//+ld9//vfb/G0uuLiYo0cOVJnnnmmvvrqK91xxx0aNGiQzjnnnCafc+SRR2rs2LG66qqrtHz5cu2+++567rnn9MQTT+iiiy7STjvtJKn23OZVV12lGTNm6IADDtBxxx2ncDist99+W3369NGNN97YqO5Bgwbpueee05gxY3TwwQfrxRdfVGFhoc4++2yVlpbqwAMPVN++fbVixQr95je/0YgRI7IGitYf2bfmUpCtdcMNN+joo4/WD3/4Q5155plat26d7rzzTg0fPrxdL1t62WWX6eGHH9b48eP185//XHl5efrDH/6gfv36qbS0dIu+uyNGjJDneZo1a5bWr1+vcDisAw88UD179mxVPQsWLNDMmTM1ceJEDRgwQKWlpXrkkUf0wQcf6IYbbtiiK9G1WlsN164fgt/UbVMffPCBmTBhgonFYqZLly7mlFNOMWvWrGlVvZsOc1+5cqWZOHGiKSwsNPn5+eaII44wn3zySc723nPPPWaXXXYxoVDI7LTTTub222/PmsZQb/369SYSiZjjjjuuyddeP9y/pe1Mp9Nm++23N3vuuWeTdRpjzMUXX2wGDhxowuGw6dGjhzn55JPNp59+2qjcVVddZUaMGGGKiopMMBg0/fr1Mz/96U9zvp/Nac0w/rKyMnPdddeZPfbYw+Tn55tQKGR22GEHM3HixKzpEK3x6quvmv33399EIhHTo0cPM2XKlKwpLfWqq6vNJZdcYnr37m3C4bDZe++9zTPPPNNs/Vs77enuu+82ksyCBQu26Pn1mppepk2mp7RU/XS49957r9XPbem0p/ppKLluDafKHHfccaagoMAsX7486/n1U2VmzZpljDFm2bJl5vTTTzcDBw400WjURCIRM2zYMHPNNdeYioqKZttT/1n+6U9/MldccYXp2bOniUaj5vDDD8+6CqAxua/UVV5ebi6++GLTp08fEwwGzeDBg83NN9+ccztw//33mz322MOEw2HTtWtXM3r0aLNo0aKs92bTKzy9+eabpqCgwIwaNcpUVVWZefPmmQkTJpiePXuaUChk+vXrZ84991yzevXqrOd1797d/OAHP2j29Td1pa5NX2uuaU/GGPPoo4+aIUOGmHA4bIYPH24WLFhgjj/+eDNkyJBGz811pS5tMg21JdOejDFmyZIl5oADDjDhcNj07dvX3Hjjjeb//u//jKSsbVZTV83KNW3p3nvvNQMHDjSe5zU7BaqpaU/vvPOOOfLII832229vQqGQyc/PNyNHjjSPPfZYk3W19bQnx5hv8ew4AOvUX01pW/zFp85m6dKlGjZsmJ566qlW9zC1hREjRqhHjx5tOjWrJS666CL9/ve/V0VFRZMDudrKmDFjlEwm9cQTTygUCuWcitecyspKVVdX6+c//7mefPLJNutV4MrtAGCJxYsXa7/99mv3ME4mk0qlUlnLXnrpJf373//WmDFj2nXdm17roaSkRLNnz9bIkSPbPYzr/f3vf2/1tRIaqr/mQlvPBOAI+TuitLS0yfnXUu1o7vYaRdjcT0BGo1EVFRW1y7qbk06ncw6Kayg/P79F54sTiUSzUyOKiopaNM++LetqDkfI3z3Lly/XuHHjdOqpp6pPnz766KOPdPfdd6uoqEgffPBB1q/jtbURI0ZozJgxGjp0qL766ivdd999+vLLL/XCCy9o1KhR7bbeev/85z8z85h79OiR9St2LfXxxx/r888/lyQFAoG224lps85vWK25c/zt+Us4m1uvpDb9paPWqj9HtrlbSy8rWX9Oc3O3lp4fbsu6mrM1l87EtqmsrMyccMIJmfOlXbt2NRMnTsxcMrQ9XXHFFWbw4MEmGo2aWCxmRo4cmXU+/ruMI+TviIZ7hblEo9Emf7lpazV3tbA+ffq06EpI7aGmpkavvfbaZssMHDhQAwcObLaudevWNXlx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",
      "text/plain": [
       "<Figure size 600x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "退出\n",
      "标记完成 ✅\n",
      "有问题的 panel_id: []\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import json\n",
    "import re\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.patches as patches\n",
    "from PIL import Image\n",
    "from IPython.display import clear_output\n",
    "\n",
    "# 输入结果 JSON 文件\n",
    "RESULT_JSON = \"/home/zhangbo/workspace/aigc/genome/qa_design/patch_generate_fixed.json\"\n",
    "\n",
    "# 加载结果\n",
    "with open(RESULT_JSON, \"r\", encoding=\"utf-8\") as f:\n",
    "    results = json.load(f)\n",
    "\n",
    "bad_panels = []  # 记录有问题的 panel_id\n",
    "\n",
    "def parse_answer(answer_raw):\n",
    "    \"\"\"清理 markdown 并解析 JSON\"\"\"\n",
    "    answer_str = answer_raw.replace(\"```json\", \"\").replace(\"```\", \"\").strip()\n",
    "    return json.loads(answer_str)\n",
    "\n",
    "def parse_grid(answer_json):\n",
    "    \"\"\"从 mask_caption 提取行列数\"\"\"\n",
    "    caption = answer_json.get(\"mask_caption\", \"\").lower()\n",
    "    match = re.search(r\"(\\d+)\\s*-\\s*row\\s*by\\s*(\\d+)\\s*-\\s*column\", caption)\n",
    "    if match:\n",
    "        rows, cols = int(match.group(1)), int(match.group(2))\n",
    "    else:\n",
    "        num_blocks = answer_json.get(\"num_blocks\", 1)\n",
    "        rows, cols = 1, num_blocks\n",
    "    return rows, cols\n",
    "\n",
    "def visualize_panel(panel):\n",
    "    \"\"\"显示单张图像及分块可视化\"\"\"\n",
    "    img_path = os.path.join(\"/home/zhangbo/workspace/aigc/genome\", panel[\"mask_path\"])\n",
    "    img = Image.open(img_path)\n",
    "    panel_path = img_path.replace(\"mask\", \"panel\")\n",
    "    panel_image = Image.open(panel_path)\n",
    "    panel_width, panel_height = panel_image.size\n",
    "    img = img.resize((panel_width, panel_height))\n",
    "\n",
    "    answer_json = parse_answer(panel[\"answer\"])\n",
    "    mask_blocks = answer_json.get(\"mask\", [])\n",
    "    rows, cols = parse_grid(answer_json)\n",
    "\n",
    "    fig, ax = plt.subplots(figsize=(6, 6))\n",
    "    ax.imshow(img)\n",
    "    ax.set_title(f\"{panel['panel_id']} | {rows}x{cols} blocks, highlight {mask_blocks}\")\n",
    "\n",
    "    block_w = panel_width / cols\n",
    "    block_h = panel_height / rows\n",
    "\n",
    "    for i in range(rows):\n",
    "        for j in range(cols):\n",
    "            idx = i*cols + j + 1\n",
    "\n",
    "            # 框颜色\n",
    "            edgecolor = \"red\" if idx in mask_blocks else \"gray\"\n",
    "            zorder = 3 if idx in mask_blocks else 1\n",
    "\n",
    "            # 绘制方框\n",
    "            rect = patches.Rectangle(\n",
    "                (j*block_w, i*block_h), block_w, block_h,\n",
    "                linewidth=2, edgecolor=edgecolor, facecolor=\"none\", zorder=zorder\n",
    "            )\n",
    "            ax.add_patch(rect)\n",
    "\n",
    "            # 计算块中心点坐标\n",
    "            center_x = j*block_w + block_w/2\n",
    "            center_y = i*block_h + block_h/2\n",
    "\n",
    "            # 绘制绿色编号（居中显示）\n",
    "            ax.text(center_x, center_y, str(idx),\n",
    "                    color=\"lime\", fontsize=14, weight=\"bold\", ha=\"center\", va=\"center\", zorder=4)\n",
    "\n",
    "    plt.axis(\"off\")\n",
    "    plt.show()\n",
    "\n",
    "# --- 交互逻辑 ---\n",
    "i = 0\n",
    "while i < len(results):\n",
    "    clear_output(wait=True)  # 清空上一次输出\n",
    "    print(f\"处理 {i+1}/{len(results)}: {results[i]['panel_id']}\")\n",
    "    visualize_panel(results[i])\n",
    "\n",
    "    cmd = input(\"回车=下一张 | w=标记问题 | q=退出: \")\n",
    "    if cmd.strip().lower() == \"w\":\n",
    "        bad_panels.append(results[i][\"panel_id\"])\n",
    "        print(f\"⚠️ 已标记有问题: {results[i]['panel_id']}\")\n",
    "        i += 1\n",
    "    elif cmd.strip().lower() == \"q\":\n",
    "        print(\"退出\")\n",
    "        break\n",
    "    elif cmd == \"\":  # 回车\n",
    "        i += 1\n",
    "    else:\n",
    "        print(\"无效输入，默认下一张\")\n",
    "        i += 1\n",
    "\n",
    "print(\"标记完成 ✅\")\n",
    "print(\"有问题的 panel_id:\", bad_panels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.根据黑白掩码自动校对mask编号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "修正 2010072777_FG_004_7_1_4 -> [2, 4, 6]\n",
      "修正 2010072785_FG_004_6_1_1 -> [3, 4, 5, 6]\n",
      "修正 2010072793_FG_004_15_1_6 -> [1, 2]\n",
      "修正 2010072793_FG_004_15_1_7 -> [1]\n",
      "修正 2010072793_FG_004_15_1_8 -> [3]\n",
      "修正 2010072795_FG_004_7_1_7 -> [5]\n",
      "修正 2010072825_FG_004_19_2_1 -> [1, 2, 3, 4]\n",
      "修正 2010072850_FG_004_5_1_1 -> [2, 4, 6]\n",
      "修正 2010072870_FG_004_5_1_1 -> [1, 2, 3]\n",
      "修正 2010072881_FG_004_4_7_1 -> [1, 2, 3, 4]\n",
      "✅ 修正完成，已保存到 /home/zhangbo/workspace/aigc/genome/qa_design/patch_generate_fixed.json\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import json\n",
    "import re\n",
    "import numpy as np\n",
    "from PIL import Image\n",
    "\n",
    "# 输入/输出 JSON\n",
    "RESULT_JSON = \"/home/zhangbo/workspace/aigc/genome/qa_design/patch_generate.json\"\n",
    "OUTPUT_JSON = RESULT_JSON.replace(\".json\", \"_fixed.json\")\n",
    "\n",
    "def parse_answer(answer_raw):\n",
    "    \"\"\"清理 markdown 并解析 JSON\"\"\"\n",
    "    answer_str = answer_raw.replace(\"```json\", \"\").replace(\"```\", \"\").strip()\n",
    "    return json.loads(answer_str)\n",
    "\n",
    "def parse_grid(answer_json):\n",
    "    \"\"\"从 mask_caption 提取行列数\"\"\"\n",
    "    caption = answer_json.get(\"mask_caption\", \"\").lower()\n",
    "    match = re.search(r\"(\\d+)\\s*-\\s*row\\s*by\\s*(\\d+)\\s*-\\s*column\", caption)\n",
    "    if match:\n",
    "        rows, cols = int(match.group(1)), int(match.group(2))\n",
    "    else:\n",
    "        num_blocks = answer_json.get(\"num_blocks\", 1)\n",
    "        rows, cols = 1, num_blocks\n",
    "    return rows, cols\n",
    "\n",
    "def detect_mask_blocks(mask_path, rows, cols, threshold=0.5):\n",
    "    \"\"\"\n",
    "    根据 mask 图计算需要的块编号\n",
    "    - 黑色区域(接近0)为目标\n",
    "    - threshold: 黑色像素比例阈值（超过就判定为 mask 块）\n",
    "    \"\"\"\n",
    "    img = Image.open(mask_path).convert(\"L\")  # 转灰度\n",
    "    arr = np.array(img) / 255.0  # 归一化到 [0,1]\n",
    "\n",
    "    h, w = arr.shape\n",
    "    block_h, block_w = h // rows, w // cols\n",
    "\n",
    "    mask_blocks = []\n",
    "    for i in range(rows):\n",
    "        for j in range(cols):\n",
    "            idx = i * cols + j + 1\n",
    "            block = arr[i*block_h:(i+1)*block_h, j*block_w:(j+1)*block_w]\n",
    "            black_ratio = 1.0 - block.mean()  # 黑色比例\n",
    "            if black_ratio >= threshold:\n",
    "                mask_blocks.append(idx)\n",
    "    return mask_blocks\n",
    "\n",
    "def main():\n",
    "    with open(RESULT_JSON, \"r\", encoding=\"utf-8\") as f:\n",
    "        results = json.load(f)\n",
    "\n",
    "    fixed_results = []\n",
    "    for panel in results:\n",
    "        try:\n",
    "            answer_json = parse_answer(panel[\"answer\"])\n",
    "            rows, cols = parse_grid(answer_json)\n",
    "\n",
    "            mask_path = os.path.join(\"/home/zhangbo/workspace/aigc/genome\", panel[\"mask_path\"])\n",
    "            if not os.path.exists(mask_path):\n",
    "                print(f\"⚠️ mask不存在: {mask_path}\")\n",
    "                fixed_results.append(panel)\n",
    "                continue\n",
    "\n",
    "            mask_blocks = detect_mask_blocks(mask_path, rows, cols, threshold=0.01)\n",
    "\n",
    "            # 更新 answer_json 里的 mask\n",
    "            answer_json[\"mask\"] = mask_blocks\n",
    "            panel[\"answer\"] = json.dumps(answer_json, indent=2, ensure_ascii=False)\n",
    "\n",
    "            print(f\"修正 {panel['panel_id']} -> {mask_blocks}\")\n",
    "        except Exception as e:\n",
    "            print(f\"⚠️ 解析失败 {panel['panel_id']} : {e}\")\n",
    "        fixed_results.append(panel)\n",
    "\n",
    "    # 保存修正后的 JSON\n",
    "    with open(OUTPUT_JSON, \"w\", encoding=\"utf-8\") as f:\n",
    "        json.dump(fixed_results, f, indent=2, ensure_ascii=False)\n",
    "\n",
    "    print(f\"✅ 修正完成，已保存到 {OUTPUT_JSON}\")\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    main()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "genome",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.23"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
